﻿using MP3Sharp.Support;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace MP3SharpFix
{
    static class Mp3Reader
    {
        //members



        /// <summary>
        /// 
        /// </summary>
        static byte[] bufHeader = new byte[4];

        static Mp3Frame tempHeader = new Mp3Frame();

        #region Const Values
        public const int MPEG2_LSF = 0;

        public const int MPEG25_LSF = 2; // SZD
        public const int MPEG1 = 1;

        public const int STEREO = 0;
        public const int JOINT_STEREO = 1;
        public const int DUAL_CHANNEL = 2;
        public const int SINGLE_CHANNEL = 3;
        public const int FOURTYFOUR_POINT_ONE = 0;
        public const int FOURTYEIGHT = 1;
        public const int THIRTYTWO = 2;



        public static readonly int[][] frequencies =
    {
            new[] {22050, 24000, 16000, 1}, new[] {44100, 48000, 32000, 1},
            new[] {11025, 12000, 8000, 1}
        }; // SZD: MPEG25

        // E.B -> private to public
        public static readonly int[][][] bitrates =
        {
            new[]
            {
                new[]
                {
                    0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000,
                    256000, 0
                },
                new[]
                {
                    0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000,
                    160000,
                    0
                },
                new[]
                {
                    0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000,
                    160000,
                    0
                }
            },
            new[]
            {
                new[]
                {
                    0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000,
                    416000,
                    448000, 0
                },
                new[]
                {
                    0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000,
                    384000, 0
                },
                new[]
                {
                    0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000,
                    320000, 0
                }
            },
            new[]
            {
                new[]
                {
                    0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000,
                    256000, 0
                },
                new[]
                {
                    0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000,
                    160000,
                    0
                },
                new[]
                {
                    0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000,
                    160000,
                    0
                }
            }
        };

        // E.B -> private to public
        public static readonly string[][][] bitrate_str =
        {
            new[]
            {
                new[]
                {
                    "free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", "96 kbit/s",
                    "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s",
                    "256 kbit/s", "forbidden"
                },
                new[]
                {
                    "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s", "48 kbit/s",
                    "56 kbit/s",
                    "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
                    "forbidden"
                },
                new[]
                {
                    "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s", "48 kbit/s",
                    "56 kbit/s",
                    "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
                    "forbidden"
                }
            },
            new[]
            {
                new[]
                {
                    "free format", "32 kbit/s", "64 kbit/s", "96 kbit/s", "128 kbit/s", "160 kbit/s", "192 kbit/s",
                    "224 kbit/s", "256 kbit/s", "288 kbit/s", "320 kbit/s", "352 kbit/s", "384 kbit/s", "416 kbit/s",
                    "448 kbit/s", "forbidden"
                },
                new[]
                {
                    "free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", "96 kbit/s",
                    "112 kbit/s", "128 kbit/s", "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s", "320 kbit/s",
                    "384 kbit/s", "forbidden"
                },
                new[]
                {
                    "free format", "32 kbit/s", "40 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s",
                    "96 kbit/s", "112 kbit/s", "128 kbit/s", "160 kbit/s", "192 kbit/s", "224 kbit/s", "256 kbit/s",
                    "320 kbit/s", "forbidden"
                }
            },
            new[]
            {
                new[]
                {
                    "free format", "32 kbit/s", "48 kbit/s", "56 kbit/s", "64 kbit/s", "80 kbit/s", "96 kbit/s",
                    "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s", "176 kbit/s", "192 kbit/s", "224 kbit/s",
                    "256 kbit/s", "forbidden"
                },
                new[]
                {
                    "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s", "48 kbit/s",
                    "56 kbit/s",
                    "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
                    "forbidden"
                },
                new[]
                {
                    "free format", "8 kbit/s", "16 kbit/s", "24 kbit/s", "32 kbit/s", "40 kbit/s", "48 kbit/s",
                    "56 kbit/s",
                    "64 kbit/s", "80 kbit/s", "96 kbit/s", "112 kbit/s", "128 kbit/s", "144 kbit/s", "160 kbit/s",
                    "forbidden"
                }
            }
        };

        #endregion
        public static bool TestHeaderByte4(int headerInt, bool bfirst = false, bool single_ch = false)
        {
            bool sync = false;
            sync = ((headerInt & 0xFFE00000) == 0xFFE00000); // SZD: MPEG 2.5


            //第一帧不能检查，因为第一帧没有前一帧
            if (!bfirst)//这个检查是每一帧都检查声道数是不是一致，有没有必要。。。
            {
                bool currentsingle = (headerInt & 0x000000C0) == 0x000000C0;
                sync = currentsingle == single_ch;
            }

            // filter out invalid sample rate
            if (sync)
            {
                sync = (((SupportClass.URShift(headerInt, 10)) & 3) != 3);
                if (!sync) Trace.WriteLine("INVALID SAMPLE RATE DETECTED", "Bitstream");
            }
            // filter out invalid layer
            if (sync)
            {
                sync = (((SupportClass.URShift(headerInt, 17)) & 3) != 0);
                if (!sync) Trace.WriteLine("INVALID LAYER DETECTED", "Bitstream");
            }
            // filter out invalid version
            if (sync)
            {
                sync = (((SupportClass.URShift(headerInt, 19)) & 3) != 1);
                if (!sync) Console.WriteLine("INVALID VERSION DETECTED");
            }

            return sync;
        }

        //这个是非流式的，也可以做流式的
        //public static Mp3Data Open(System.IO.Stream stream)
        //{
        //    return new Mp3Data(stream);
        //}
        //public static Mp3Data ReadAll(System.IO.Stream stream)
        //{
        //    Mp3Data mp3data = new Mp3Data(null);
        //    //bool bfirst = true;
        //    //bool single_ch_mode = false;
        //    Mp3Frame frameLast = null;
        //    while (true)
        //    {
        //        if (ReadHeaderInt(stream, out int headerInt))
        //        {
                   
        //            if (Mp3IDFrame.TryRead(stream, headerInt, out Mp3IDFrame idframe))
        //            {
        //                mp3data.ids.Add(idframe);
        //            }
        //            else if (Mp3RiffFrame.TryRead(stream, headerInt, out Mp3RiffFrame riffFrame))
        //            {

        //            }
        //            else if (ParseFrameHeader(stream, headerInt, out Mp3Frame frame))//这是个无聊的检查, bfirst, single_ch_mode))
        //            {
        //                if (frameLast != null)
        //                {
        //                    var nexthead = frameLast.framedataaddress + frameLast.framesize + 4;
        //                    if (frame.framedataaddress == nexthead)
        //                    {
        //                        //address succ
        //                        mp3data.frames.Add(frameLast);
        //                    }
        //                }
        //                frame.ReadData(stream);
        //                ////计算对齐到4字节，不够补齐
        //                //int len = frame.framesize / 4;
        //                //if (frame.framesize % 4 != 0)
        //                //    len++;

        //                //frame.framedata = new byte[len * 4];
        //                //stream.Read(frame.framedata, 0, frame.framesize);

        //                //first是特别的，做个无聊的检查
        //                frameLast = frame;
        //                //if (bfirst)
        //                //{
        //                //    bfirst = false;
        //                //    single_ch_mode = frame.h_mode == SINGLE_CHANNEL;
        //                //}
        //            }
        //            else
        //            {
        //                throw new Exception("error format.");
        //            }
        //        }
        //        else
        //        {
        //            mp3data.vbrInfo = mp3data.frames[0].ParseVBR();
        //            if(mp3data.vbrInfo!=null)//有vbr信息的情况下，第一帧不要
        //            {
        //                mp3data.frames.RemoveAt(0);
        //            }
        //            //读没了
        //            mp3data.frames.Add(frameLast);
        //            return mp3data;
        //        }
        //    }
        //}

        public static bool ReadHeaderInt(System.IO.Stream stream, out int headerInt)
        {
            int len = stream.Read(bufHeader, 0, 4);
            if (len < 4)
            {
                headerInt = 0;
                return false;
            }
            headerInt = bufHeader[0] << 24 | bufHeader[1] << 16 | bufHeader[2] << 8 | bufHeader[3];
            return true;
        }
        public static bool ParseFrameHeader(System.IO.Stream stream, int headerInt, out Mp3Frame frame, bool bFirst=true, bool single_ch_mode=false)
        {


            //处理了ID头以后，就不用考虑错误了
            bool bfind = TestHeaderByte4(headerInt, bFirst, single_ch_mode);
            if (!bfind)
            {
                frame = null;
                return false;
            }
            //tempHeader._headerstring = headerInt;
            
            //do  //首先检测Header是否合法，不合法推一个字节继续
            //{
            //    headerInt <<= 8;
            //    int len2 = stream.Read(bufHeader, 3, 1);
            //    if (len2 < 1)
            //        return null;
            //    headerInt |= (bufHeader[3] & 0x000000FF);

            //    bfind = TestHeaderByte4(headerInt, bFirst, single_ch_mode);
            //} while (!bfind);



            //if (bFirst)
            //这个玩意，是不是第一帧都可以有
            {
                tempHeader.h_version = ((SupportClass.URShift(headerInt, 19)) & 1);
                if (((SupportClass.URShift(headerInt, 20)) & 1) == 0)
                    // SZD: MPEG2.5 detection
                    if (tempHeader.h_version == MPEG2_LSF)
                        tempHeader.h_version = MPEG25_LSF;
                    else
                        throw new Exception("BitstreamErrors.UNKNOWN_ERROR");

                if ((tempHeader.h_sample_frequency = ((SupportClass.URShift(headerInt, 10)) & 3)) == 3)
                {
                    throw new Exception("BitstreamErrors.UNKNOWN_ERROR");
                }
            }

            int channel_bitrate = 0;

            tempHeader.h_layer = 4 - (SupportClass.URShift(headerInt, 17)) & 3;
            tempHeader.h_protection_bit = (SupportClass.URShift(headerInt, 16)) & 1;
            tempHeader.h_bitrate_index = (SupportClass.URShift(headerInt, 12)) & 0xF;
            tempHeader.h_padding_bit = (SupportClass.URShift(headerInt, 9)) & 1;
            tempHeader.h_mode = ((SupportClass.URShift(headerInt, 6)) & 3);
            tempHeader.h_mode_extension = (SupportClass.URShift(headerInt, 4)) & 3;
            if (tempHeader.h_mode == JOINT_STEREO)
                tempHeader.h_intensity_stereo_bound = (tempHeader.h_mode_extension << 2) + 4;
            else
                tempHeader.h_intensity_stereo_bound = 0;
            // should never be used
            if (((SupportClass.URShift(headerInt, 3)) & 1) == 1)
                tempHeader.h_copyright = true;
            if (((SupportClass.URShift(headerInt, 2)) & 1) == 1)
                tempHeader.h_original = true;

            // calculate number of subbands:
            if (tempHeader.h_layer == 1)
                tempHeader.h_number_of_subbands = 32;
            else
            {
                channel_bitrate = tempHeader.h_bitrate_index;
                // calculate bitrate per channel:
                if (tempHeader.h_mode != SINGLE_CHANNEL)
                    if (channel_bitrate == 4)
                        channel_bitrate = 1;
                    else
                        channel_bitrate -= 4;

                if ((channel_bitrate == 1) || (channel_bitrate == 2))
                    if (tempHeader.h_sample_frequency == THIRTYTWO)
                        tempHeader.h_number_of_subbands = 12;
                    else
                        tempHeader.h_number_of_subbands = 8;
                else if ((tempHeader.h_sample_frequency == FOURTYEIGHT) || ((channel_bitrate >= 3) && (channel_bitrate <= 5)))
                    tempHeader.h_number_of_subbands = 27;
                else
                    tempHeader.h_number_of_subbands = 30;
            }
            if (tempHeader.h_intensity_stereo_bound > tempHeader.h_number_of_subbands)
                tempHeader.h_intensity_stereo_bound = tempHeader.h_number_of_subbands;

            // calculate framesize and nSlots
            tempHeader.calculate_framesize();

            tempHeader.framedataaddress = (uint)stream.Position;

            //always new
            frame = tempHeader;
            tempHeader = new Mp3Frame();
            return true;
        }
    }
}
